package com.tarena.lbs.message.web.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.base.protocol.pager.BasePageList;
import com.tarena.lbs.basic.api.UserGroupApi;
import com.tarena.lbs.common.message.util.TimeUtil;
import com.tarena.lbs.message.web.mapper.MsgMapper;
import com.tarena.lbs.message.web.mapper.TimingMsgTemplateMapper;
import com.tarena.lbs.message.web.mapper.XxlJobInfoMapper;
import com.tarena.lbs.message.web.service.TimingMsgTaskService;
import com.tarena.lbs.message.web.service.xxljobhandler.TimingMsgGlueJobHandlerString;
import com.tarena.lbs.pojo.message.dos.Msg;
import com.tarena.lbs.pojo.message.dos.TaskInfo;
import com.tarena.lbs.pojo.message.dos.TimingMsgTemplate;
import com.tarena.lbs.pojo.message.dos.XxlJobInfo;
import com.tarena.lbs.pojo.message.param.TimingMsgTaskInsertParam;
import com.tarena.lbs.pojo.message.param.TimingMsgTaskQueryParam;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Options;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * 定时消息任务实现类
 */
@Service
@Slf4j
public class TimingMsgTaskServiceImpl implements TimingMsgTaskService {

    @Autowired
    XxlJobInfoMapper xxlJobInfoMapper;

    @Autowired
    MsgMapper msgMapper;

    @Autowired
    TimingMsgTemplateMapper timingMsgTemplateMapper;

    @Resource
    private UserGroupApi userGroupApi;

    /**
     * 添加定时消息任务
     * @param timingMsgTaskInsertParam 定时消息任务数据
     * @return
     */
    @Override
    @Options(useGeneratedKeys = true, keyProperty = "id")
    public Boolean insert(TimingMsgTaskInsertParam timingMsgTaskInsertParam) {
        log.info("insert timingMsgTaskInsertParam={}",JSONObject.toJSONString(timingMsgTaskInsertParam));
        //1, 定时消息任务保成到xxl-job框架xxl-job-info表
        //1.1 获取系统当前时间
        Date currentSystemTime = TimeUtil.getCurrentSystemTime();
        //1.2 创建数据访问层实体类对象
        XxlJobInfo xxlJobInfo = new XxlJobInfo();
        //1.3 设置定时任务组的编号，给固定值
        xxlJobInfo.setJobGroup(1);
        //1.4 设置定时任务描述
        xxlJobInfo.setJobDesc(timingMsgTaskInsertParam.getTaskName());
        //1.5 设置定时任务添加时间
        xxlJobInfo.setAddTime(currentSystemTime);
        //1.6 设置定时任务更新时间
        xxlJobInfo.setUpdateTime(currentSystemTime);
        //1.7 设置定时任务负责人
        xxlJobInfo.setAuthor("lbs管理员");
        //1.8 设置定时任务告警邮箱
        xxlJobInfo.setAlarmEmail("lbs@tedu.cn");
        //1.9 设置定时任务调度类型为cron表达式
        xxlJobInfo.setScheduleType("CRON");
        //1.10 设置定时任务 cron表达式的值
        xxlJobInfo.setScheduleConf(timingMsgTaskInsertParam.getCron());
        //1.11 设置定时任务调度过期策略
        xxlJobInfo.setMisfireStrategy("DO_NOTHING");
        //1.12 设置定时任务路由策略
        xxlJobInfo.setExecutorRouteStrategy("FIRST");
        //1.13 设置定时任务执行超时时间
        xxlJobInfo.setExecutorTimeout(0);
        //1.14 设置定时任务失败重试次数
        xxlJobInfo.setExecutorFailRetryCount(0);
        //1.15 设置定时任务阻塞情况时的处理策略
        xxlJobInfo.setExecutorBlockStrategy("DISCARD_LATER");
        //1.16 设置定时任务执行代码的类型，GLUE_GROOVY：Groovy脚本模式，任务是一个Groovy脚本，可以在管理界面在线编写和维护。
        xxlJobInfo.setGlueType("GLUE_GROOVY");
        //1.17 设置定时任务标记
        xxlJobInfo.setGlueRemark(String.valueOf(timingMsgTaskInsertParam.getTempId()));
        //1.18 设置定时任务状态，1表示启用
        xxlJobInfo.setTriggerStatus(1);
        //1.19 设置定时任务上一次执行时间
        xxlJobInfo.setTriggerLastTime(0L);

        //创建Cron 表达式生成时间序列类，
        CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(timingMsgTaskInsertParam.getCron(), TimeZone.getTimeZone("Asia/Shanghai"));
        Date nextDate = new Date();
        //计算出下一次任务应该执行的时间点
        nextDate = cronSequenceGenerator.next(nextDate);
        //1.20 设置定时任务
        xxlJobInfo.setTriggerNextTime(nextDate.getTime());

        int insertRow = xxlJobInfoMapper.insert(xxlJobInfo);

        //从xxl-job-info表读取任务编号
        Integer taskId = xxlJobInfo.getId();
        //修改java代码中的任务编号
        String updateJavaCode= TimingMsgGlueJobHandlerString.javaCode.replaceAll("taskId", taskId.toString());
       //2 java代码保成到xxl-job框架xxl-job-info表
        xxlJobInfo.setGlueSource(updateJavaCode);
        xxlJobInfo.setGlueUpdatetime(currentSystemTime);
        //更新xxl-job-info表中信息。
        int updateRow = xxlJobInfoMapper.updateByPrimaryKeySelective(xxlJobInfo);


        //3,任务消息保存到msg表
        // 3.1 根据模板编号从定时任务模板表中查询消息标题，正文
        TimingMsgTemplate timingMsgTemplate = timingMsgTemplateMapper.selectByPrimaryKey(timingMsgTaskInsertParam.getTempId());
        String msgTitle = timingMsgTemplate.getMsgTitle();
        String content = timingMsgTemplate.getContent();
        //获取用户list
        List<Integer> userIdList = userGroupApi.getUserByTargetGroup(timingMsgTaskInsertParam.getUserList());
        //3.2 保存消息内容到msg表中
        if(!CollectionUtils.isEmpty(userIdList)){
            log.info("准备给用户发送消息 userIdList={}", JSONObject.toJSONString(userIdList));
            for (Integer userId : userIdList) {
                Msg msg = new Msg();
                msg.setUserId(userId);
                msg.setTimingMsgTaskId(taskId);
                msg.setStatus(0);//定时消息不可读
                msg.setMsgTitle(msgTitle);
                msg.setContent(content);
                msg.setActivityId(timingMsgTemplate.getActivityId());
                msg.setTemplateId(timingMsgTaskInsertParam.getTempId());

                insertRow = msgMapper.insert(msg);
                if (insertRow < 1) {
                    throw new RuntimeException("保存定时消息失败");
                }

            }
        }


        return true;
    }

    @Override
    public BasePageList<TaskInfo> getTaskList(TimingMsgTaskQueryParam param) {
        int pageSize = param.getPageSize();
        int pageNum = param.getPageNo();
        //new PageQuery(pageNum, pageSize);
        List<TaskInfo> taskList =  xxlJobInfoMapper.getTaskList(param);
        PageInfo<TaskInfo> pageInfo = new PageInfo<>(taskList);
        return new BasePageList<TaskInfo>(taskList,Long.valueOf(pageInfo.getTotal()));
    }


}
